#pragma once
#include "level.hpp"
#include "util.hpp"
#include "format.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include <atomic>
#include <mutex>
#include <cstdarg>
#include <unordered_map>

namespace log
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger() {}
        Logger(const std::string &name, Format::ptr &fmt, log::Level level, std::vector<Sink::ptr> &sinks)
            : _name(name), _fmt(fmt), _level(level), _sinks(sinks.begin(), sinks.end())
        {
        }
        const std::string& getLoggerName()
        {
            return _name;
        }
        void debug(const std::string &file, int line, const std::string &fmt, ...)
        {
            // 等级小于输出等级,直接返回
            if (log::DEBUG < _level)
            {
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vsprintf is fail" << std::endl;
                return;
            }
            va_end(ap);
            serialize(line, file, log::DEBUG, res);
            free(res);
        }
        void info(const std::string &file, int line, const std::string &fmt, ...)
        {
            // 等级小于输出等级,直接返回
            if (log::INFO < _level)
            {
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vsprintf is fail" << std::endl;
                return;
            }
            va_end(ap);
            serialize(line, file, log::INFO, res);
            free(res);
        }
        void warnning(const std::string &file, int line, const std::string &fmt, ...)
        {
            // 等级小于输出等级,直接返回
            if (log::WARNNING < _level)
            {
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vsprintf is fail" << std::endl;
                return;
            }
            va_end(ap);
            serialize(line, file, log::WARNNING, res);
            free(res);
        }
        void error(const std::string &file, int line, const std::string &fmt, ...)
        {
            // 等级小于输出等级,直接返回
            if (log::ERROR < _level)
            {
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vsprintf is fail" << std::endl;
                return;
            }
            va_end(ap);
            serialize(line, file, log::ERROR, res);
            free(res);
        }
        int fatal(const std::string &file, int line, const std::string &fmt, ...)
        {
            // 等级小于输出等级,直接返回
            if (log::FATAL < _level)
            {
                return 0;
            }
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vsprintf is fail" << std::endl;
                return 0;
            }
            va_end(ap);
            int size = serialize(line, file, log::FATAL, res);
            free(res);
            return size;
        }

    protected:
        // 返回落地内容的大小
        int serialize(int line, const std::string &file, log::Level level, char *res)
        {
            LogMsg msg(line, _name, file, res, level);
            std::stringstream ss;
            _fmt->format(ss, msg);
            logOut(ss.str().c_str(), ss.str().size());
            return ss.str().size();
        }

        virtual void logOut(const char *msg, int len) = 0;

    protected:
        std::mutex _mtx;
        std::string _name;
        Format::ptr _fmt;
        std::atomic<log::Level> _level;
        std::vector<Sink::ptr> _sinks;
    };

    // 同步日志器
    class SyncLogger : public Logger
    {
    public:
        SyncLogger() {}
        SyncLogger(const std::string &name, Format::ptr &fmt, log::Level level, std::vector<Sink::ptr> &sinks)
            : Logger(name, fmt, level, sinks)
        {
        }

    protected:
        void logOut(const char *msg, int len)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            if (_sinks.empty())
            {
                return;
            }
            for (const auto &e : _sinks)
            {
                e->logOut(msg, len);
            }
        }
    };

    // 异步日志器
    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(const std::string &name, Format::ptr &fmt, log::Level level, std::vector<Sink::ptr> &sinks, AsyncType looper_type)
            : Logger(name, fmt, level, sinks)
            , _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLogOut, this, std::placeholders::_1), looper_type))
        {
        }
        // 将数据写入_looper的生产缓冲区
        void logOut(const char *msg, int len) override
        {
            _looper->push(msg, len);
        }
        // 实际的落地
        void realLogOut(Buffer &buffer)
        {
            if (_sinks.empty())
            {
                return;
            }
            for (const auto &e : _sinks)
            {
                e->logOut(buffer.begin(), buffer.readAbleLen());
            }
        }

    private:
        AsyncLooper::ptr _looper;
    };

    enum LoggerType
    {
        SYNC_LOGGER,
        ASYNC_LOGGER
    };

    class LoggerBuilder
    {
    public:
        LoggerBuilder() : _type(SYNC_LOGGER), _level(DEBUG), _looper_type(ASYNC_SAFE)
        {
        }
        void BuilderEnableUnsafeAsync()
        {
            _looper_type = ASYNC_UNSAFE;
        }
        void BuilderType(LoggerType type)
        {
            _type = type;
        }
        void BuilderName(const std::string &name)
        {
            _name = name;
        }
        void BuilderFormat(const std::string &pattern)
        {
            _fmt = std::make_shared<Format>(pattern);
        }
        void BuilderLevel(log::Level level)
        {
            _level = level;
        }
        template <typename SinkType, typename... Args>
        void BuilderSink(Args &&...args)
        {
            Sink::ptr sink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(sink);
        }
        virtual Logger::ptr Build() = 0;

    protected:
        AsyncType _looper_type;
        LoggerType _type;
        std::string _name;
        Format::ptr _fmt;
        log::Level _level;
        std::vector<Sink::ptr> _sinks;
    };

    class LocalLoggerBuiler : public LoggerBuilder
    {
    public:
        Logger::ptr Build() override
        {
            assert(!_name.empty());
            if (_fmt.get() == nullptr)
            {
                _fmt = std::make_shared<Format>();
            }
            if (_sinks.empty())
            {
                BuilderSink<StdOutSink>();
            }
            if (_type == ASYNC_LOGGER)
            {
                return std::make_shared<AsyncLogger>(_name, _fmt, _level, _sinks, _looper_type);
            }
            return std::make_shared<SyncLogger>(_name, _fmt, _level, _sinks);
        }
    };

    class LoggerManager
    {
    public:
        static LoggerManager& getInstance()
        {
            static LoggerManager ins;
            return ins;
        }
        //添加日志器
        void addLogger(const Logger::ptr& logger)
        {
            if(hasLogger(logger->getLoggerName()))
            {
                return;
            }
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->getLoggerName(), logger));
        } 
        //判断该日志器是否存在
        bool hasLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            const auto& it = _loggers.find(name);
            //找不到
            if(it == _loggers.end())
            {
                return false;
            }
            return true;
        } 
        //获取指定日志器
        Logger::ptr getLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            const auto& it = _loggers.find(name);
            //找不到
            if(it == _loggers.end())
            {
                return Logger::ptr();
            }
            return it->second;
        }
        //获取默认日志器
        Logger::ptr getRootLogger()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _root_logger;
        }
    private:
        LoggerManager()
        {
            std::unique_ptr<LoggerBuilder> builder(new LocalLoggerBuiler());
            builder->BuilderName("root");
            _root_logger = builder->Build();
            _loggers.insert(std::make_pair("root", _root_logger));
        }
    private:
        std::mutex _mutex;
        Logger::ptr _root_logger; //默认日志器
        std::unordered_map<std::string, Logger::ptr> _loggers; //日志器名称->日志器
    };

    class GlobalLoggerBuiler : public LoggerBuilder
    {
    public:
        Logger::ptr Build() override
        {
            assert(!_name.empty());
            if (_fmt.get() == nullptr)
            {
                _fmt = std::make_shared<Format>();
            }
            if (_sinks.empty())
            {
                BuilderSink<StdOutSink>();
            }
            Logger::ptr logger;
            if (_type == ASYNC_LOGGER)
            {
                logger = std::make_shared<AsyncLogger>(_name, _fmt, _level, _sinks, _looper_type);
            }
            else
            {
                logger = std::make_shared<SyncLogger>(_name, _fmt, _level, _sinks);
            }
            LoggerManager::getInstance().addLogger(logger);
            return logger;
        }
    };
};